package com.msh.frame.client.common;

import com.alibaba.fastjson.JSON;
import com.msh.frame.client.base.IConvert;
import com.msh.frame.client.exception.BizException;

import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author shihu 通用的返回数据类
 * @author shihu
 */
public class Result<T> implements Serializable {

  private Integer code = 0;
  private String msg;
  private T result;
  private Integer count;

  private static final Result<Boolean> SUCESS_RESULT = new Result<>(Boolean.TRUE);
  private static final Result<Void> VoID_RESULT = new Result<>();

  public Result() {
  }

  public Result(T result) {
    this.result = result;
  }

  public Result(int code, String msg) {
    this.code = code;
    this.msg = msg;
  }

  public static <T> Result<T> successReturn(T t) {
    return new Result<>(t);
  }

  public static Result<Boolean> successReturn() {
    return SUCESS_RESULT;
  }

  public static Result<Void> voidReturn() {
    return VoID_RESULT;
  }

  public static <T> Result<T> errorServerReturn() {
    return new Result<>(ErrorCode.SYSTEM_ERROR.getCode(), ErrorCode.SYSTEM_ERROR.getMsg());
  }

  public static <T> Result<T> errorReturn(String message) {
    return new Result<>(ErrorCode.BIZ_ERROR.getCode(), message);
  }

  public static <T> Result<T> errorReturn(int code, String message) {
    return new Result<>(code, message);
  }

  public static <T> Result<T> errorReturn(ErrorCode errorCode) {
    return new Result<>(errorCode.getCode(), errorCode.getMsg());
  }

  public Integer getCode() {
    return code;
  }

  public Result<T> setCode(Integer code) {
    this.code = code;
    return this;
  }

  public String getMsg() {
    return msg;
  }

  public Result<T> setMsg(String msg) {
    this.msg = msg;
    return this;
  }


  public T data() {
    BizException.doThrowIfTrue(this, 0 != code);
    return result;
  }

  @Deprecated
  public T getResult() {
    return result;
  }

  public Result<T> setResult(T result) {
    this.result = result;
    return this;
  }

  public Integer getCount() {
    return count;
  }

  public Result<T> setCount(Integer count) {
    this.count = count;
    return this;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    boolean nullFlag = false;
    sb.append("CommonResult{");
    if (null != code) {
      if (nullFlag) {
        sb.append(",code=").append(code);
      } else {
        sb.append("code=").append(code);
        nullFlag = true;
      }
    }
    if (null != msg) {
      if (nullFlag) {
        sb.append(",msg='").append(msg).append('\'');
      } else {
        sb.append("msg='").append(msg).append('\'');
        nullFlag = true;
      }
    }
    if (null != result) {
      if (nullFlag) {
        sb.append(",result=").append(result);
      } else {
        sb.append("result=").append(result);
        nullFlag = true;
      }
    }
    if (null != count) {
      if (nullFlag) {
        sb.append(",count=").append(count);
      } else {
        sb.append("count=").append(count);
        nullFlag = true;
      }
    }
    sb.append('}');
    return sb.toString();
  }

  public String toJsonString() {
    return JSON.toJSONString(this);
  }

  public static <ScouceT extends IConvert, TargetT extends IConvert> Result<TargetT> convertObj(
      Result<ScouceT> s, Class<TargetT> tClazz) {
    if (!Integer.valueOf(0).equals(s.getCode())) {
      return errorReturn(s.getCode(), s.getMsg());
    }
    TargetT convert = s.getResult().convert(tClazz);
    return Result.successReturn(convert)
        .setCount(s.getCount());
  }

  public static <ScouceT extends IConvert, TargetT extends IConvert> Result<List<TargetT>> convertList(
      Result<List<ScouceT>> s, Class<TargetT> tClazz) {
    if (!Integer.valueOf(0).equals(s.getCode())) {
      return errorReturn(s.getCode(), s.getMsg());
    }
    return Result
        .successReturn(
            s.getResult().stream()
                .map(o -> o.convert(tClazz))
                .collect(Collectors.toList())
        )
        .setCount(s.getCount());
  }
}
